<template>
  <el-form v-bind="getBindValue" :class="getFormClass" ref="formElRef" :model="formModel">
    <el-row v-bind="getRow">
      <slot name="formHeader"></slot>
      <template v-for="schema in getSchema" :key="schema.field">
        <FormItem :schema="schema" :formProps="getProps" :formModel="formModel" :setFormModel="setFormModel">
        </FormItem>
      </template>
    </el-row>
  </el-form>
</template>
<script setup lang="ts">
import { useDesign } from "@/hooks/web/useDesign";
import { dateUtil } from "@/utils/dateUtils";
import { computed, onMounted, reactive, Ref, ref, unref, useAttrs, watch } from "vue";
import { dateItemType } from "./helper";
import { useFormValues } from "./hooks/useFormValues";
import { FormActionType, FormProps, FormSchema } from "./types/form";
import { Nullable, Recordable } from "/#/global";
import { deepMerge } from '@/utils';
import { useFormEvents } from "./hooks/useFormEvents";
import { basicProps } from "./props";
import FormItem from './components/FormItem.vue';
import cloneDeep from "lodash-es/cloneDeep";

const emit = defineEmits<{
  (e: 'register', instance: FormActionType): void,
  (e: 'field-value-change', key: string, value: any): void
}>()
const attrs = useAttrs()
const props = defineProps(basicProps)
const propsRef = ref<Partial<FormProps>>({});
const { prefixCls } = useDesign('basic-form');

const formModel = reactive<Recordable>({});
const defaultValueRef = ref<Recordable>({});
const schemaRef = ref<Nullable<FormSchema[]>>(null);
const formElRef = ref<Nullable<FormActionType>>(null);



const getProps = computed((): FormProps => {
  return { ...props, ...unref(propsRef) } as FormProps;
});

const getBindValue = computed(
  () => ({ ...attrs, ...props, ...unref(getProps) } as Recordable),
);

const getFormClass = computed(() => {
  return [
    prefixCls
  ];
});

const getSchema = computed((): FormSchema[] => {
  const schemas: FormSchema[] = unref(schemaRef) || (unref(getProps).schemas as any);
  for (const schema of schemas) {
    const { defaultValue, component } = schema;
    // 日期类型组件
    if (defaultValue && dateItemType.includes(component)) {
      if (!Array.isArray(defaultValue)) {
        schema.defaultValue = dateUtil(defaultValue);
      } else {
        const def: any[] = [];
        defaultValue.forEach((item) => {
          def.push(dateUtil(item));
        });
        schema.defaultValue = def;
      }
    }
  }
  if (unref(getProps).showAdvancedButton) {
    return schemas.filter((schema) => schema.component !== 'ElDivider') as FormSchema[];
  } else {
    return schemas as FormSchema[];
  }
});


// 初始化form默认值
const { handleFormValues, initDefault } = useFormValues({
  getProps,
  defaultValueRef,
  getSchema,
  formModel,
});
const { getFieldsValue, setFieldsValue, resetSchema, validateField, validate, resetFields, updateSchema } = useFormEvents({
  emit,
  getProps,
  formModel,
  getSchema,
  defaultValueRef,
  formElRef: formElRef as Ref<FormActionType>,
  schemaRef: schemaRef as Ref<FormSchema[]>,
  handleFormValues,
})

async function setProps(formProps: Partial<FormProps>): Promise<void> {
  propsRef.value = deepMerge(unref(propsRef) || {}, formProps);
}

const formActionType: FormActionType = {
  getFieldsValue,
  setProps,
  setFieldsValue,
  resetSchema,
  validateField,
  resetFields,
  updateSchema,
  validate
}

onMounted(() => {
  initDefault();
  emit('register', formActionType);
});

// 监听修改schemas配置
watch(() => unref(getProps).schemas,
  (schemas) => {
    resetSchema(schemas ?? []);
  })

// Get uniform row style and Row configuration for the entire form
const getRow = computed((): Recordable => {
  const { baseRowStyle = {}, rowProps } = unref(getProps);
  return {
    style: baseRowStyle,
    ...rowProps,
  };
});

function setFormModel(key: string, value: any) {
  console.log(value)
  formModel[key] = value
  const { validateTrigger } = unref(getBindValue);
  if (!validateTrigger || validateTrigger === 'update:modelValue') {
    validateField([key]).catch((_) => { });
  }
  emit('field-value-change', key, value);
}
</script>
